package com.hup.utils.io.csv;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * @author hugan
 * @date 2019/8/31
 */
public class CsvUtil {

    /**
     * 构造输出csv文件的writer;编码是UTF8-带BOM;
     * 解决win10和Excel的中文乱码问题(也可以直接使用GBK就不用处理BOM问题,但UTF比较'通用'?)
     */
    public static OutputStreamWriter getUTF8Writer(File file) throws IOException {
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(new byte[] { (byte) 0xEF, (byte) 0xBB,(byte) 0xBF });//要用fos才能写入BOM
        /*
        V1.1 直接用FileOutputStream;
          win10家庭版: 用notepad+UTF8打开正常.其他编码则乱码
          win10企业版: 用notepad+ANSI打开正常.同上
        V1.2FileOutputStream+BOM
          解决Excel打开中文乱码
        V2.0 使用OutputStreamWriter+FileOutputStream+BOM
          解决上述所有问题
         */
        return new OutputStreamWriter(fos, StandardCharsets.UTF_8);
    }

    public static <T> CsvData<T> read(String path, boolean addRowCountColumn, CsvHandler<T> handler) throws IOException {
        File file = new File(path);
        CSVFormat csvFormat = CSVFormat.POSTGRESQL_CSV;
        //这里要指定编码,否则开发时可能没问题,但单独运行jar时乱码
        try (CSVParser parse = CSVParser.parse(new FileInputStream(file), StandardCharsets.UTF_8, csvFormat)) {
            CsvData<T> res = new CsvData<>();
            res.fileName = file.getName();

            Iterator<CSVRecord> it = parse.iterator();
            CSVRecord next;
            if (!it.hasNext() || (next = it.next()) == null) {
                throw new IOException("文件内容为空");
            }

            //head
            int headSize = next.size();
            res.heads = new String[addRowCountColumn ? headSize + 1 : headSize];
            if (addRowCountColumn) {
                res.heads[0] = "行";
            }
            for (int i = 0; i < next.size(); i++) {
                res.heads[addRowCountColumn ? i + 1 : i] = next.get(i);
            }

            //rows
            res.lstRow = new ArrayList<>();
            int rowIndex = 1;
            while (it.hasNext()) {
                next = it.next();
                int size = next.size();
                T row = null;
                for (int i = 0; i < size; i++) {
                    row = handler.handleRow(rowIndex, row, i, next.get(i));
                }
                rowIndex++;
                res.lstRow.add(row);
            }

            return res;
        }
    }

    public interface CsvHandler<T> {
        /**
         * @param rowIndex 起始于1
         * @param row 第一次调用时是null
         */
        T handleRow(int rowIndex, T row, int colIndex, String val);
    }

    public static class CsvData<T> {
        public String fileName;
        public String[] heads;
        public ArrayList<T> lstRow;

        @Override
        public String toString() {
            return "CsvData{" +
                    "fileName=" + fileName +
                    ", lstRow=" + (lstRow == null ? null : lstRow.size()) +
                    '}';
        }

        public int getRowCount() {
            return lstRow == null ? 0 : lstRow.size();
        }
    }

}
